﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="CreateIndex.cs" company="SmartPlan">
//   SmartPlan 2011
// </copyright>
// <summary>
//   The create index.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace DbDiff.Common.Scripting
{
    using System;
    using System.Data;
    using DataAccess;

    /// <summary>
    /// The create index.
    /// </summary>
    internal class CreateIndex : CreateBase
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="CreateIndex"/> class.
        /// </summary>
        /// <param name="schema">
        /// The schema.
        /// </param>
        /// <param name="tableName">
        /// The table name.
        /// </param>
        /// <param name="indexName">
        /// The index name.
        /// </param>
        /// <param name="databaseDataSets">
        /// The dt objects.
        /// </param>
        /// <param name="scrOption">
        /// The scr option.
        /// </param>
        public CreateIndex(string schema, string tableName, string indexName, DatabaseDataSets databaseDataSets, SqlScriptingOption scrOption)
            : base(schema, tableName, indexName, databaseDataSets, scrOption)
        {
        }

        /// <summary>
        /// Gets or sets The table index row for scipting
        /// </summary>
        protected DbObjectsDs.IndexRow IndexRow { get; set; }


        /// <summary>
        /// The set rows.
        /// </summary>
        protected override void SetRows()
        {
            this.DataRowViews = this.DatabaseDiffData.GetIndex(this.Schema, this.TableName, this.Name);
        }

        /// <summary>
        /// The set current row.
        /// </summary>
        protected override void SetCurrentRow()
        {
            if (this.DataRowViews != null && this.DataRowViews.Length > 0)
            {
                this.IndexRow = (DatabaseDataSets.IndexRow)this.DataRowViews[this.CurrentRow].Row;
            }
        }

        /// <summary>
        /// A kulcsokat itt rakjuk bele
        /// </summary>
        /// <returns>
        /// Returns the index keys
        /// </returns>
        protected virtual string Keys()
        {
            string keys = string.Empty;
            DataRowView[] drv = this.DatabaseDiffData.GetIndexKeys(this.Schema, this.TableName, this.IndexRow.Name);
            DbObjectsDs.IndexKeyRow irk = null;

            if (drv.Length > 0)
            {
                foreach (DataRowView t in drv)
                {
                    irk = (DatabaseDataSets.IndexKeyRow)t.Row;

                    // included mezőket nem rakjuk bele
                    if (!irk.IsIncluded)
                    {
                        keys += QuoteName(irk.ColumnName) + (irk.IsDescending ? " " + cmdDesc : string.Empty) + Comma;
                    }
                }
            }

            keys = keys.Remove(keys.LastIndexOf(Comma), 1);

            return keys;
        }

        /// <summary>
        /// Itt az include mezőket kell visszaadni
        /// </summary>
        /// <returns>
        /// The include column.
        /// </returns>
        protected virtual string IncludeColumn()
        {
            string includeColumn = string.Empty;
            DataRowView[] drv = this.DatabaseDiffData.GetIndexKeys(this.Schema, this.TableName, this.IndexRow.Name);
            DbObjectsDs.IndexKeyRow irk = null;

            if (drv.Length > 0)
            {
                foreach (DataRowView t in drv)
                {
                    irk = (DatabaseDataSets.IndexKeyRow)t.Row;

                    // included mezőket nem rakjuk bele
                    if (irk.IsIncluded)
                    {
                        includeColumn += QuoteName(irk.ColumnName) + (irk.IsDescending ? " " + cmdDesc : string.Empty) + Comma;
                    }
                }
            }

            if (!String.IsNullOrEmpty(includeColumn))
            {
                includeColumn = includeColumn.Remove(includeColumn.LastIndexOf(Comma), 1);
            }

            return includeColumn;
        }

        /// <summary>
        /// The index name.
        /// </summary>
        /// <returns>
        /// returns the index name.
        /// </returns>
        protected string IndexName()
        {
            return this.IndexRow.NoName ? string.Empty : QuoteName(this.IndexRow.Name);
        }

        /// <summary>
        /// The unique.
        /// </summary>
        /// <returns>
        /// Return the unique.
        /// </returns>
        protected string Unique()
        {
            return this.IndexRow.IsUnique ? cmdUnique : string.Empty;
        }

        /// <summary>
        /// The clustered.
        /// </summary>
        /// <returns>
        /// The clustered. index
        /// </returns>
        protected string Clustered()
        {
            string retval = !this.IndexRow.IsConstraint | (this.IndexRow.IsConstraint & !this.IndexRow.IsPrimaryKey)
                                ? (this.IndexRow.IsClustered ? cmdClustered : string.Empty)
                                : (this.IndexRow.IsClustered ? string.Empty : "NON" + cmdClustered);

            return retval;
        }

        /// <summary>
        /// The index type.
        /// </summary>
        /// <returns>
        /// Returns the index type
        /// </returns>
        protected string IndexType()
        {
            string s;
            if (!this.IndexRow.IsXmlIndex)
            {
                s = this.IndexRow.IsConstraint
                        ? (this.IndexRow.IsPrimaryKey & this.IndexRow.IsUnique ? cmdPrimary : cmdUnique)
                        : cmdIndex;

                return s;
            }

            switch (this.IndexRow.SecondaryXmlIndex)
            {
                case 0:
                    s = "PRIMARY XML INDEX";
                    break;
                default:
                    s = "XML INDEX";
                    break;
            }

            return s;
        }

        /// <summary>
        /// The file group.
        /// </summary>
        /// <returns>
        /// The file group.
        /// </returns>
        protected string FileGroup()
        {
            // todo schema ON partition_scheme_name(column_name)
            return string.Format(string.Format("{0} {{0}}", cmdOn), QuoteName(this.IndexRow.IndexFileGroupIsDefault ? "DEFAULT" : this.IndexRow.IndexFileGroup));
        }

        /*
                <relational_index_option> ::=
        {
            PAD_INDEX = { ON | OFF } ok
          | FILLFACTOR =fillfactor ok
          | SORT_IN_TEMPDB = { ON | OFF } 
          | IGNORE_DUP_KEY = { ON | OFF } ok
          | STATISTICS_NORECOMPUTE = { ON | OFF } ok
          | DROP_EXISTING = { ON | OFF } 
          | ONLINE = { ON | OFF } 
          | ALLOW_ROW_LOCKS = { ON | OFF } ok
          | ALLOW_PAGE_LOCKS = { ON | OFF } ok
          | MAXDOP =max_degree_of_parallelism
          | DATA_COMPRESSION = { NONE | ROW | PAGE} 
             [ ON PARTITIONS ( { <partition_number_expression> | <range> } 
             [ , ...n ] ) ]
        }
        */

        /// <summary>
        /// The index option.
        /// </summary>
        /// <returns>
        /// Return the index option
        /// </returns>
        protected string IndexOption()
        {
            string retval = string.Empty;

            if (!this.IndexRow.IsConstraint)
            {
                retval += string.Format("{0} = {1}, ", cmdPadIndex, this.IndexRow.IsPadIndex ? cmdOn : cmdOff);
            }

            if (this.IndexRow.IndexFillFactor != 0)
            {
                retval += string.Format(string.Format("{0} = {{0}}, ", cmdFillFactor), this.IndexRow.IndexFillFactor);
            }

            if (!this.IndexRow.IsConstraint)
            {
                retval += string.Format("{0} = {1}, ", cmdIgnoreDupKey, this.IndexRow.IgnoreDupKey == 1 ? cmdOn : cmdOff);
                retval += string.Format("{0} = {1}, ", cmdNoReCompute, this.IndexRow.NoRecompute ? cmdOn : cmdOff);
               
            }

            //.IsDisabled
            //SORT_IN_TEMPDB = { ON | OFF } 
            //DROP_EXISTING = { ON | OFF } 
            //ONLINE = { ON | OFF } 
            // MAXDOP =max_degree_of_parallelism
            //DATA_COMPRESSION = { NONE | ROW | PAGE} 
            // [ ON PARTITIONS ( { <partition_number_expression> | <range> } 
            // [ , ...n ] ) ]
            
            retval += string.Format("ALLOW_ROW_LOCKS = {0}, ", this.IndexRow.IsPageLockAllowed ? cmdOn : cmdOff);
            retval += string.Format("ALLOW_PAGE_LOCKS = {0}, ", this.IndexRow.IsRowLockAllowed ? cmdOn : cmdOff);
            
            if (retval.Length > 0)
            {
                retval = string.Format("{0}WITH ({1})", CrLf, retval.Remove(retval.LastIndexOf(Comma), 1)).TrimEnd(' ');
            }

            return retval;
        }

        /// <summary>
        /// The row script.
        /// </summary>
        protected override void RowScript()
        {
            if (this.IndexRow == null)
            {
                return;
            }

            // include column berakása
            string includeColumn = this.IncludeColumn();
            string indexOptions = this.IndexOption();

            this.AddElement(cmdCreate, false, true);
            this.AddElement(this.Unique(), false, true);
            this.AddElement(this.Clustered(), false, true);
            this.AddElement(this.IndexType(), false, true);
            this.AddElement(this.IndexName(), false, true);
            this.AddElement(cmdOn, false, true);
            this.AddElement(QuoteName(this.Schema, this.TableName), false, true);
            this.AddElement(string.Format("({0}){1}", this.Keys(), includeColumn != string.Empty ? string.Format(" INCLUDE ({0})", includeColumn) : string.Empty), false, true);

            if (this.IndexRow.HasFilter)
            {
                this.AddElement(this.FilteredIndex(), false, true);
            }
           
            if (!this.IndexRow.IsXmlIndex)
            {
                this.AddElement(indexOptions, false, true);
                this.AddElement(this.FileGroup(), false, true);
            }

            if (this.IndexRow.SecondaryXmlIndex > 0)
            {
               this.AddElement(this.SecondaryXmlIndex(), false, true);
               this.AddElement(indexOptions, false, true);
            }

            this.AddCommandTerminator(string.Empty);
            this.AddRow();
        }

        /// <summary>
        /// Returns filtered index
        /// </summary>
        /// <returns>
        /// Returns the filter
        /// </returns>
        protected string FilteredIndex()
        {
            return this.IndexRow.HasFilter
                       ? string.Empty
                       : string.Format("{0}WHERE {1}", CrLf, this.IndexRow.FilterDefinition);
        }

        /// <summary>
        /// Create secondary index for clause
        /// </summary>
        /// <returns>
        /// string.Format("USING XML INDEX {0} FOR ", this.IndexRow.PrimaryXmlIndexName)
        /// </returns>
        protected string SecondaryXmlIndex()
        {
            string s = string.Format("{0}USING XML INDEX {1} FOR ", CrLf, QuoteName(this.IndexRow.PrimaryXmlIndexName));
            switch (this.IndexRow.SecondaryXmlIndex)
            {
                case 1:
                    s += "PATH";
                    break;
                case 2:
                    s += "PROPERTY";
                    break;
                case 3:
                    s += "VALUE";
                    break;
            }

            return s;
        }
    }
}